﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace TradeClient.Logic
{
    class ChartCandlestick
    {
        private Chart chart;
        private ChartArea chartAreaCandlestick;
        private Series seriesCandlestick;

        /// <summary>
        /// 创建一个股价图表控件
        /// </summary>
        /// <param name="controlContainer">容纳该控件的父控件</param>
        public ChartCandlestick(System.Windows.Forms.Control controlContainer)
        {
            initChart();
            controlContainer.Controls.Add(chart);
        }

        public void Display()
        {
            scaleViewZoom(10, 50);
        }

        /// <summary>
        /// 图表区名称
        /// </summary>
        public string ChartAreaName { get { return "Candlestick"; } }

        /// <summary>
        /// 创建属于该图表的数据序列
        /// </summary>
        /// <param name="seriesName">要创建的数据序列名称</param>
        /// <returns>数据序列</returns>
        public Series CreateSeries(string seriesName)
        {
            seriesCandlestick = chart.Series.Add(seriesName);

            //数据序列样式
            seriesCandlestick.ChartArea = "";
            seriesCandlestick.ChartType = SeriesChartType.Candlestick;
            seriesCandlestick.IsXValueIndexed = true;
            seriesCandlestick.XValueType = ChartValueType.DateTime;

            //k线颜色
            seriesCandlestick.SetCustomProperty("PriceUpColor", "Red");
            seriesCandlestick.SetCustomProperty("PriceDownColor", "Aquamarine");

            return seriesCandlestick;
        }

        /// <summary>
        /// 获取指定的数据序列
        /// </summary>
        /// <param name="seriesName">数据序列名称</param>
        /// <returns>数据序列</returns>
        public Series GetSeries(string seriesName)
        {
            return chart.Series[seriesName];
        }

        /// <summary>
        /// 创建属于该图表的注解
        /// </summary>
        /// <returns></returns>
        public void CreateAnnotation(Annotation aa)
        {
            chart.Annotations.Add(aa);
        }

        public void FlashView()
        {
            double min = chartAreaCandlestick.AxisX.Minimum;
            double max = chartAreaCandlestick.AxisX.Maximum;

            scaleViewZoom(min, max);
        }



        //激活控件以便接收按键事件
        private void chart_Click(object sender, EventArgs e)
        {
            chart.Select();
        }

        private bool isViewCursor;

        //移动十字光标线
        private void chart_MouseMove(object sender, MouseEventArgs e)
        {
            if (isViewCursor)
            {
                chartAreaCandlestick.CursorX.SetCursorPixelPosition(new PointF(e.X, e.Y), true);
                chartAreaCandlestick.CursorY.SetCursorPixelPosition(new PointF(e.X, e.Y), true);

                //显示光标处K线数据
                int index = int.Parse(chartAreaCandlestick.CursorX.Position.ToString()) - 1;
                if (index >= 0 && index <= seriesCandlestick.Points.Count - 1) setTitle(seriesCandlestick.Points[index]);
            }
        }

        //打开/关闭十字光标线
        private void chart_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            //关闭十字光标线
            if (e.Button == System.Windows.Forms.MouseButtons.Left && isViewCursor)
            {
                isViewCursor = false;
                chartAreaCandlestick.CursorX.Position = -1;
                chartAreaCandlestick.CursorY.Position = -1;
            }
            //打开十字光标线
            else if (e.Button == System.Windows.Forms.MouseButtons.Left && !isViewCursor)
            {
                isViewCursor = true;
            }
        }

        //使箭头键引发KeyDown事件
        private void chart_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right) e.IsInputKey = true;
        }

        //按键处理
        private void chart_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Up:
                    viewZoom("ZoomOut");
                    break;
                case Keys.Down:
                    viewZoom("ZoomIn");
                    break;
                case Keys.Left:
                    viewMove(Keys.Left);
                    break;
                case Keys.Right:
                    viewMove(Keys.Right);
                    break;
            }
        }

        //视图缩放（以右侧为基准向左缩放，除非达到右边界）
        private void viewZoom(string dirc)
        {
            double axisXMinimum = chartAreaCandlestick.AxisX.Minimum;
            double axisXMaximun = chartAreaCandlestick.AxisX.Maximum;
            double viewXMinimum = chartAreaCandlestick.AxisX.ScaleView.ViewMinimum;
            double viewXMaximum = chartAreaCandlestick.AxisX.ScaleView.ViewMaximum;

            //缩放起始位置，结束位置，步长，最大值，最小值
            double startPosition = 0, endPosition = 0, step = 10;

            //缩小
            if (dirc == "ZoomIn")
            {
                //达到右边界则往左收缩
                if (viewXMaximum >= axisXMaximun)
                { startPosition = (viewXMinimum - step) < axisXMinimum ? axisXMinimum : (viewXMinimum - step); endPosition = viewXMaximum; }
                else
                { startPosition = viewXMinimum + 1; endPosition = (viewXMaximum + step) > axisXMaximun ? axisXMaximun : (viewXMaximum + step); }
            }
            //放大
            else
            {
                //达到右边界则往左放大
                if (viewXMaximum >= axisXMaximun)
                { startPosition = (viewXMinimum + step) < (viewXMaximum - step) ? (viewXMinimum + step) : (viewXMaximum - step); endPosition = viewXMaximum; }
                else
                { startPosition = viewXMinimum + 1; endPosition = (viewXMaximum - step) < (startPosition + step) ? (startPosition + step) : (viewXMaximum - step); }
            }

            scaleViewZoom(startPosition, endPosition);
        }

        //缩放视图
        private void scaleViewZoom(double startPosition, double endPosition)
        {
            //重新计算图表属性
            chartAreaCandlestick.RecalculateAxesScale();

            double start = startPosition > chartAreaCandlestick.AxisX.Minimum ? startPosition : chartAreaCandlestick.AxisX.Minimum;
            double end = endPosition < chartAreaCandlestick.AxisX.Maximum ? endPosition : chartAreaCandlestick.AxisX.Maximum;

            setAxisYLimitToScaleView(start, end);
            chartAreaCandlestick.AxisX.ScaleView.Zoom(start, end);
        }

        //用左右箭头键移动视图
        private void viewMove(Keys key)
        {
            double step = 10, scroll = 0;
            double axisXMaximum = chartAreaCandlestick.AxisX.Maximum;
            double viewMinimum = chartAreaCandlestick.AxisX.ScaleView.ViewMinimum;
            double viewMaximum = chartAreaCandlestick.AxisX.ScaleView.ViewMaximum;

            if (key == Keys.Left && viewMinimum > 0)
            {
                scroll = (viewMinimum - step) < 0 ? 0 : (viewMinimum - step);
                setAxisYLimitToScaleView(scroll, viewMaximum - step);
                chartAreaCandlestick.AxisX.ScaleView.Scroll(scroll);

            }
            else if (key == Keys.Right && viewMaximum < axisXMaximum)
            {
                double newViewMax = viewMaximum + step;
                scroll = newViewMax > axisXMaximum ? viewMinimum + (newViewMax - axisXMaximum) : viewMinimum + step;
                setAxisYLimitToScaleView(scroll, viewMaximum + step);
                chartAreaCandlestick.AxisX.ScaleView.Scroll(scroll + 2);
            }
        }

        //设置标题
        private void setTitle(DataPoint dp)
        {
            chartAreaCandlestick.AxisX2.Title = "[" + DateTime.FromOADate(dp.XValue).AddMinutes(1).ToString("yyyy-MM-dd HH:mm") + "]" + "  收盘：" + dp.YValues[3] + "  最高：" + dp.YValues[0] + "  最低：" + dp.YValues[1] + "  开盘：" + dp.YValues[2];
        }

        //找出视图范围内的最大最小值
        private void setAxisYLimitToScaleView(double startPosition, double endPosition)
        {
            double maxY = 0, minY = 0;

            this.GetLimitFormSeries(seriesCandlestick, (int)startPosition, (int)endPosition, out maxY, out minY);

            double padding = (maxY - minY) * 0.05;
            chartAreaCandlestick.AxisY.Minimum = minY - padding;
            chartAreaCandlestick.AxisY.Maximum = maxY + padding;
        }

        /// <summary>
        /// 获取指定Series范围内的最大值和最小值
        /// </summary>
        /// <param name="series">数据序列</param>
        /// <param name="startPosition">开始位置</param>
        /// <param name="endPosition">结束位置</param>
        /// <param name="maxY">最大值</param>
        /// <param name="minY">最小值</param>
        private void GetLimitFormSeries(Series series, int startPosition, int endPosition, out double maxY, out double minY)
        {
            double high = 0, low = 0; maxY = 0; minY = double.MaxValue;
            int start = startPosition < 0 ? 0 : startPosition;
            int end = endPosition >= series.Points.Count ? series.Points.Count - 1 : endPosition;

            for (int i = start; i <= end; i++)
            {
                high = series.Points[i].YValues[0];
                low  = series.Points[i].YValues[1];

                if (high > maxY) maxY = high;
                if (low  < minY) minY = low;
            }
        }

        //设置图表显示区样式
        private void initChart()
        {
            //初始化控件
            chart = new Chart();
            chartAreaCandlestick = chart.ChartAreas.Add(this.ChartAreaName);

            //图表区样式
            chart.Dock = DockStyle.Fill;
            chart.BackColor = Color.Black;
            chart.AntiAliasing = AntiAliasingStyles.All;

            //图表K线图区样式
            chartAreaCandlestick.Position.Width = 100;
            chartAreaCandlestick.Position.Height = 100;
            chartAreaCandlestick.BackColor = Color.Black;

            //光标样式
            chartAreaCandlestick.CursorX.LineColor = Color.White;
            chartAreaCandlestick.CursorY.LineColor = Color.White;
            chartAreaCandlestick.CursorX.AxisType = AxisType.Primary;
            chartAreaCandlestick.CursorY.AxisType = AxisType.Primary;
            chartAreaCandlestick.CursorX.AutoScroll = true;
            chartAreaCandlestick.CursorY.AutoScroll = true;
            chartAreaCandlestick.CursorX.IsUserEnabled = false;
            chartAreaCandlestick.CursorY.IsUserEnabled = false;

            //主轴线字体颜色
            chartAreaCandlestick.AxisX.LineColor = Color.DarkRed;
            chartAreaCandlestick.AxisY.LineColor = Color.DarkRed;
            chartAreaCandlestick.AxisX.TitleForeColor = Color.White;
            chartAreaCandlestick.AxisY.TitleForeColor = Color.White;

            //主轴线标签样式
            chartAreaCandlestick.AxisX.LabelStyle.Angle = 0;
            chartAreaCandlestick.AxisX.LabelStyle.Format = "{HH:mm}";
            chartAreaCandlestick.AxisY.LabelStyle.Format = "{d}";
            chartAreaCandlestick.AxisX.LabelStyle.ForeColor = Color.Gray;
            chartAreaCandlestick.AxisY.LabelStyle.ForeColor = Color.Gray;
            chartAreaCandlestick.AxisX.LabelStyle.Font = new System.Drawing.Font("Arial", 9);
            chartAreaCandlestick.AxisY.LabelStyle.Font = new System.Drawing.Font("Arial", 9);

            //主轴线网格样式
            chartAreaCandlestick.AxisX.MajorGrid.Enabled = false;
            chartAreaCandlestick.AxisY.MajorGrid.Enabled = true;
            chartAreaCandlestick.AxisX.MajorTickMark.Enabled = false;
            chartAreaCandlestick.AxisY.MajorTickMark.Enabled = false;
            chartAreaCandlestick.AxisY.MajorGrid.LineColor = Color.DarkRed;
            chartAreaCandlestick.AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dot;

            //主轴线间隔样式
            chartAreaCandlestick.AxisX.IsStartedFromZero = false;
            chartAreaCandlestick.AxisX.Interval = 30;
            chartAreaCandlestick.AxisX.IntervalType = DateTimeIntervalType.Minutes;
            chartAreaCandlestick.AxisY.IntervalAutoMode = IntervalAutoMode.FixedCount;

            //主轴线滚动条
            chartAreaCandlestick.AxisX.ScrollBar.Enabled = false;
            chartAreaCandlestick.AxisY.ScrollBar.Enabled = false;

            //辅助轴线样式
            chartAreaCandlestick.AxisX2.Enabled = AxisEnabled.True;
            chartAreaCandlestick.AxisY2.Enabled = AxisEnabled.False;
            chartAreaCandlestick.AxisX2.LineColor = Color.DarkRed;
            chartAreaCandlestick.AxisY2.LineColor = Color.DarkRed;
            chartAreaCandlestick.AxisX2.LabelStyle.Enabled = false;
            chartAreaCandlestick.AxisY2.LabelStyle.Enabled = false;
            chartAreaCandlestick.AxisX2.MajorGrid.Enabled = false;
            chartAreaCandlestick.AxisY2.MajorGrid.Enabled = false;
            chartAreaCandlestick.AxisX2.MajorTickMark.Enabled = false;
            chartAreaCandlestick.AxisY2.MajorTickMark.Enabled = false;

            //辅助轴标题
            chartAreaCandlestick.AxisX2.TitleForeColor = Color.White;
            chartAreaCandlestick.AxisX2.TitleAlignment = StringAlignment.Near;

            //注册事件
            chart.Click += new EventHandler(chart_Click);
            chart.MouseMove += new System.Windows.Forms.MouseEventHandler(chart_MouseMove);
            chart.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(chart_MouseDoubleClick);
            chart.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(chart_PreviewKeyDown);
            chart.KeyDown += new System.Windows.Forms.KeyEventHandler(chart_KeyDown);
        }
    }
}
